%%%-------------------------------------------------------------------
%%% File    : rdf_rs_SUITE.erl
%%% Author  :  <vjache>
%%% Description : Functinal tests for 'rdf_rs' module.
%%%
%%% Created :  8 May 2009 by  <vjache>
%%%-------------------------------------------------------------------
-module(rdf_rs_SUITE).

%% Note: This directive should only be used in test suites.
-compile(export_all).

-include_library("ct.hrl").
-include("../include/rdf_spalg.hrl"). 
-include("../include/rdf_record.hrl").
-include("../include/rdf_rs.hrl"). 
-include("../include/test.hrl"). 

%%--------------------------------------------------------------------
%% COMMON TEST CALLBACK FUNCTIONS
%%--------------------------------------------------------------------

%%--------------------------------------------------------------------
%% Function: suite() -> Info
%%
%% Info = [tuple()]
%%   List of key/value pairs.
%%
%% Description: Returns list of tuples to set default properties
%%              for the suite.
%%
%% Note: The suite/0 function is only meant to be used to return
%% default data values, not perform any other operations.
%%--------------------------------------------------------------------
suite() ->
    [{timetrap,{minutes,10}},{stylesheet,"suite_categories.css"}].

%%--------------------------------------------------------------------
%% Function: init_per_suite(Config0) ->
%%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
%%
%% Config0 = Config1 = [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%% Reason = term()
%%   The reason for skipping the suite.
%%
%% Description: Initialization before the suite.
%%
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_suite(Config) ->
 	ok=create_rdf_store(),
    Config.

%%--------------------------------------------------------------------
%% Function: end_per_suite(Config0) -> void() | {save_config,Config1}
%%
%% Config0 = Config1 = [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%%
%% Description: Cleanup after the suite.
%%--------------------------------------------------------------------
end_per_suite(_Config) ->
    ok.

%%--------------------------------------------------------------------
%% Function: init_per_testcase(TestCase, Config0) ->
%%               Config1 | {skip,Reason} | {skip_and_save,Reason,Config1}
%%
%% TestCase = atom()
%%   Name of the test case that is about to run.
%% Config0 = Config1 = [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%% Reason = term()
%%   The reason for skipping the test case.
%%
%% Description: Initialization before each test case.
%%
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_testcase(TestCase, Config) ->
%%  	load_test_data(TestCase,Config),
    Config.

%%--------------------------------------------------------------------
%% Function: end_per_testcase(TestCase, Config0) ->
%%               void() | {save_config,Config1}
%%
%% TestCase = atom()
%%   Name of the test case that is finished.
%% Config0 = Config1 = [tuple()]
%%   A list of key/value pairs, holding the test case configuration.
%%
%% Description: Cleanup after each test case.
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, _Config) ->
    ok.

%%--------------------------------------------------------------------
%% Function: sequences() -> Sequences
%%
%% Sequences = [{SeqName,TestCases}]
%% SeqName = atom()
%%   Name of a sequence.
%% TestCases = [atom()]
%%   List of test cases that are part of the sequence
%%
%% Description: Specifies test case sequences.
%%--------------------------------------------------------------------
sequences() -> 
    [].

%%--------------------------------------------------------------------
%% Function: all() -> TestCases | {skip,Reason}
%%
%% TestCases = [TestCase | {sequence,SeqName}]
%% TestCase = atom()
%%   Name of a test case.
%% SeqName = atom()
%%   Name of a test case sequence.
%% Reason = term()
%%   The reason for skipping all test cases.
%%
%% Description: Returns the list of test cases that are to be executed.
%%--------------------------------------------------------------------
all() -> 
    [friend_info,friend_info_bf,friend_info_bf1].


%%--------------------------------------------------------------------
%% TEST CASES
%%--------------------------------------------------------------------

%%--------------------------------------------------------------------
%% Function: TestCase() -> Info
%%
%% Info = [tuple()]
%%   List of key/value pairs.
%%
%% Description: Test case info function - returns list of tuples to set
%%              properties for the test case.
%%
%% Note: This function is only meant to be used to return a list of
%% values, not perform any other operations.
%%--------------------------------------------------------------------
%% friend_info() -> 
%%     [].
%% friend_info(_Config) -> 
%% 	S=subj0,
%% 	Age=age,
%% 	Name=name,
%% 	Family=family,
%% 	FriendId=friend,
%% 	VasyaLit={'$lit',"Vasya",string},
%% 	Rs=rdf_rs:new_mapped({?QUAD_TAG_SA,S,{onto,"name"},VasyaLit,'_'}, VasyaLit, S),
%% 	Rs1=rdf_rs:join_lookup_by(Rs, {?QUAD_TAG_SA,S,{onto,"friend"},FriendId,'_'}, S),
%% 	Rs2=rdf_rs:join_lookup_by(Rs1, [{?QUAD_TAG_SA,FriendId,{onto,"name"},Name,'_'},
%% 							{?QUAD_TAG_SA,FriendId,{onto,"familyName"},Family,'_'}, 
%% 							{?QUAD_TAG_SA,FriendId,{onto,"age"},Age,'_'}], FriendId),
%% 	ProjExpr=rdf_rs:project(Rs2, [S,Name]),
%% 	Pg=valg:eval(ProjExpr, pipe_console:new()),
%% 	ct:log(info,lists:flatten(valg:explain(Pg)))
%% ,
%% 	Pid=pgt:new(Pg),
%% 	ok=util:wait_finish(Pid)
%% .

friend_info() -> 
    [].
friend_info(_Config) -> 
	S=subj0,
	Age=age,
	Name=name,
	Family=family,
	FriendId=friend,
	VasyaLit={'$lit',"Vasya",string},
	Ss=rdf_sol_builder:new_from_quad({?QUAD_TAG_SA,S,{onto,"name"},VasyaLit,'_'}, VasyaLit),
	Ss1=rdf_sol_builder:join_lk(Ss, [{?QUAD_TAG_SA,S,{onto,"friend"},FriendId,'_'}], S),
	Ss2=rdf_sol_builder:join_lk(Ss1, [{?QUAD_TAG_SA,FriendId,{onto,"name"},Name,'_'},
							{?QUAD_TAG_SA,FriendId,{onto,"familyName"},Family,'_'}, 
							{?QUAD_TAG_SA,FriendId,{onto,"age"},Age,'_'}], FriendId),
	SsResult=rdf_sol_builder:project(Ss2, [S,Name,Family,Age]),
	Pg=valg2pgt:fold(SsResult#solset.expr, pipe_console:new()),
	ct:log(info,lists:flatten(valg2pgt:format(Pg))),
	Pid=pgt:new(Pg),
	ok=util:wait_finish(Pid).

friend_info_bf() -> 
    [].
friend_info_bf(Config) ->
	ResultId=make_ref(),
	S=subj0,
	Age=age,
	Name=name,
	Family=family,
	FriendId=friend,
	VasyaLit={'$lit',"Vasya",string},
	Ss=rdf_sol_builder:new_from_quad({?QUAD_TAG_SA,S,{onto,"name"},VasyaLit,'_'}, S , VasyaLit),
	Ss1=rdf_sol_builder:new_from_quad({?QUAD_TAG_SA,S,{onto,"friend"},FriendId,'_'}, S),
	Jss=rdf_sol_builder:join_bf([Ss,Ss1], S, inner),
	Jss1=rdf_sol_builder:join_bf(
	  [Jss|
		   [rdf_sol_builder:new_from_quad(QuadPatt,FriendId)||QuadPatt<-[
						 {?QUAD_TAG_SA,FriendId,{onto,"name"},Name,'_'},
						 {?QUAD_TAG_SA,FriendId,{onto,"familyName"},Family,'_'},
						 {?QUAD_TAG_SA,FriendId,{onto,"age"},Age,'_'}
						]
		   ]
	  ],FriendId,inner),
	SsResult=rdf_sol_builder:project(Jss1, [S,Name,Family,Age]),
	Pg=valg2pgt:fold(SsResult#solset.expr, pipe_result:new(ResultId, self())),%pipe_console:new()),
	ct:log(info,lists:flatten(valg2pgt:format(Pg))),
	Pid=pgt:new(Pg),
	ResultList=pipe_result:list(Pid, ResultId),
	
	ct:log(info, "~p~n", [ResultList]),
	
	assert_eq(lists:sort(ResultList),
			  lists:sort(load_test_result(friend_info_bf,Config))).
friend_info_bf1() -> 
    [].
friend_info_bf1(Config) ->
	ResultId=make_ref(),
	S=subj0,
	Age=age,
	Name=name,
	Family=family,
	FriendId=friend,
	VasyaLit={'$lit',"Vasya",string},
	Ss=rdf_sol_builder:new_from_quad({?QUAD_TAG_SA,S,{onto,"name"},VasyaLit,'_'} , VasyaLit),
	Ss1=rdf_sol_builder:new_from_quad({?QUAD_TAG_SA,S,{onto,"friend"},FriendId,'_'}),
	Jss=rdf_sol_builder:join_bf([Ss,Ss1], S, inner),
	Jss1=rdf_sol_builder:join_bf(
	  [Jss|
		   [rdf_sol_builder:new_from_quad(QuadPatt)||QuadPatt<-[
						 {?QUAD_TAG_SA,FriendId,{onto,"name"},Name,'_'},
						 {?QUAD_TAG_SA,FriendId,{onto,"familyName"},Family,'_'},
						 {?QUAD_TAG_SA,FriendId,{onto,"age"},Age,'_'}
						]
		   ]
	  ],FriendId,inner),
	SsResult=rdf_sol_builder:project(Jss1, [S,Name,Family,Age]),
	Pg=valg2pgt:fold(SsResult#solset.expr, pipe_result:new(ResultId, self())),%pipe_console:new()),
	ct:log(info,lists:flatten(valg2pgt:format(Pg))),
	Pid=pgt:new(Pg),
	ResultList=pipe_result:list(Pid, ResultId),
	
	ct:log(info, "~p~n", [ResultList]),
	
	assert_eq(lists:sort(ResultList),
			  lists:sort(load_test_result(friend_info_bf,Config))).

%%--------------------------------------------------------------------
%% Helper functions
%%--------------------------------------------------------------------
load_test_data(friend_info,Config) ->
	load_test_data(prep_friend_info,Config);
load_test_data(friend_info_bf,Config) ->
   load_test_data(prep_friend_info,Config);
load_test_data(friend_info_bf1,Config) ->
   load_test_data(prep_friend_info,Config);
load_test_data(prep_friend_info,Config) ->
	FileSource=?CONFIG(data_dir,Config)++"/friends.tup",
	Pids=[util:map_from_file(
	  FileSource, rdf_rs:vect_by_tag(Tag),
	  fun(Rec) ->
			  RecNew=rdf_record:as(Tag, Rec),
			  RecNew
	  end)||Tag<-?ALL_TAGs],
	util:wait_finish(Pids),
	?CT_LOG_INFO("RDF vectors loaded.~n",[]).
create_rdf_store() ->
	lists:foreach(fun(Tag) ->
						  ?CT_LOG_INFO(
							"[PID:~p] Create vector ~p: ~p~n",
							[self(),Tag,svc_vms:create_vect(Tag, list_to_atom("rdf_"++atom_to_list(Tag)), [])])
				  end, ?ALL_TAGs).

load_test_result(friend_info,Config) ->
	load_test_result("friend_info.list",Config);
load_test_result(friend_info_bf,Config) ->
	load_test_result("friend_info_bf.list",Config);
load_test_result(FileSource,Config) ->
	FileName=?CONFIG(data_dir,Config)++FileSource,
	{ok,[Term]}=file:consult(FileName),
	Term.

assert_eq(A,B) when A==B ->
	ok;
assert_eq(A,B) ->
	exit({assert_eq_failed,A,B}).
